from typing import List, Optional, Dict, Any
from fastapi import Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from passlib.context import CryptContext
from datetime import datetime, timedelta
import os
import shutil
import subprocess
import asyncio
import re
import hashlib
import json

from server.db.repositories.server_repository import ServerRepository
from server.db.repositories.user_repository import UserRepository
from server.schemas.server import (
    ServerCreate, ServerUpdate, ServerResponse, ServerStatusUpdate,
    ServerConfigCreate, ServerConfigUpdate, ServerBackupCreate,
    ServerModCreate, ServerModUpdate
)
from server.db.models.server import ServerStatus, ServerType
from server.core.config import settings
from server.core.security import get_current_user, require_permissions
from server.db.session import get_db
from server.core.exceptions import (
    ResourceNotFoundError, PermissionDeniedError, InvalidOperationException,
    ServerOperationError, ConfigurationError
)
from server.services.steam_service import SteamService
from server.services.backup_service import BackupService
from server.services.rcon_service import RconService
from server.services.log_service import LogService

class ServerService:
    def __init__(
        self,
        db: AsyncSession = Depends(get_db),
        server_repo: ServerRepository = Depends(),
        user_repo: UserRepository = Depends(),
        steam_service: SteamService = Depends(),
        backup_service: BackupService = Depends(),
        rcon_service: RconService = Depends(),
        log_service: LogService = Depends()
    ):
        self.db = db
        self.server_repo = server_repo
        self.user_repo = user_repo
        self.steam_service = steam_service
        self.backup_service = backup_service
        self.rcon_service = rcon_service
        self.log_service = log_service
        self.pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

    async def create_server(self, server_data: ServerCreate, current_user_id: int) -> ServerResponse:
        """创建新服务器""
        # 检查用户权限
        current_user = await self.user_repo.get_by_id(current_user_id)
        if not current_user or (current_user.role != 'admin' and not await self._has_server_creation_permission(current_user_id)):
            raise PermissionDeniedError("没有创建服务器的权限")

        # 验证服务器端口是否已被占用
        existing_server = await self.server_repo.get_server_by_ip_port(server_data.ip, server_data.port)
        if existing_server:
            raise InvalidOperationException(f"IP {server_data.ip}:{server_data.port} 已被其他服务器占用")

        # 验证安装路径
        if not os.path.isabs(server_data.install_path):
            raise ConfigurationError("安装路径必须是绝对路径")

        # 创建服务器记录
        server = await self.server_repo.create_server(server_data, current_user_id)

        # 初始化服务器配置
        await self._initialize_default_config(server.id)

        # 如果设置了自动安装，开始安装服务器
        if server_data.auto_install:
            try:
                await self.install_server(server.id, current_user_id)
            except Exception as e:
                # 安装失败，删除服务器记录
                await self.server_repo.delete_server(server.id)
                raise ServerOperationError(f"服务器安装失败: {str(e)}")

        return ServerResponse.from_orm(server)

    async def get_server(self, server_id: int, current_user_id: int) -> ServerResponse:
        """获取服务器详情""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_access_permission(server, current_user_id)

        return ServerResponse.from_orm(server)

    async def get_user_servers(self, current_user_id: int, skip: int = 0, limit: int = 20) -> List[ServerResponse]:
        """获取当前用户的服务器列表""
        servers = await self.server_repo.get_servers_by_user(current_user_id, skip, limit)
        return [ServerResponse.from_orm(server) for server in servers]

    async def get_public_servers(self, skip: int = 0, limit: int = 20) -> List[ServerResponse]:
        """获取公开服务器列表""
        servers = await self.server_repo.get_public_servers(skip, limit)
        return [ServerResponse.from_orm(server) for server in servers]

    async def update_server(self, server_id: int, server_data: ServerUpdate, current_user_id: int) -> ServerResponse:
        """更新服务器信息""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 如果修改了端口，验证新端口是否可用
        if server_data.port and server_data.port != server.port:
            existing_server = await self.server_repo.get_server_by_ip_port(server.ip, server_data.port)
            if existing_server:
                raise InvalidOperationException(f"端口 {server_data.port} 已被占用")

        # 更新服务器信息
        updated_server = await self.server_repo.update_server(server_id, server_data)

        # 如果修改了RCON密码，更新相关配置
        if server_data.rcon_password and server_data.rcon_password != server.rcon_password:
            await self.update_server_config(server_id, "ServerSettings.RCONPassword", server_data.rcon_password, current_user_id)

        return ServerResponse.from_orm(updated_server)

    async def delete_server(self, server_id: int, current_user_id: int) -> bool:
        """删除服务器""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 如果服务器正在运行，先停止
        if server.status == ServerStatus.RUNNING.value:
            await self.stop_server(server_id, current_user_id, "删除服务器前停止")

        # 删除服务器文件（如果设置了自动删除）
        if settings.AUTO_DELETE_SERVER_FILES:
            try:
                if os.path.exists(server.install_path):
                    shutil.rmtree(server.install_path)
            except Exception as e:
                # 记录警告日志，但继续删除数据库记录
                await self.log_service.add_system_log(
                    log_level="warning",
                    message=f"删除服务器文件失败: {str(e)}",
                    details={"server_id": server_id, "path": server.install_path}
                )

        # 删除数据库记录
        return await self.server_repo.delete_server(server_id)

    async def start_server(self, server_id: int, current_user_id: int, comment: str = "手动启动") -> ServerStatusUpdate:
        """启动服务器""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 检查服务器状态
        if not server.can_start():
            raise InvalidOperationException(f"服务器当前状态为 {server.status}，无法启动")

        # 检查服务器是否已安装
        if not await self._is_server_installed(server):
            raise InvalidOperationException("服务器尚未安装，请先安装")

        # 更新状态为启动中
        await self.server_repo.update_server_status(server_id, ServerStatus.STARTING.value, current_user_id, comment)

        try:
            # 启动服务器进程
            await self._execute_server_start(server)

            # 等待服务器启动
            await self._wait_for_server_start(server_id)

            # 更新状态为运行中
            status_history = await self.server_repo.update_server_status(
                server_id, ServerStatus.RUNNING.value, current_user_id, comment
            )

            # 记录日志
            await self.log_service.add_server_log(
                server_id=server_id,
                log_type="system",
                log_level="info",
                message=f"服务器启动成功",
                source="server_service",
                details={"pid": server.pid}
            )

            return ServerStatusUpdate(
                server_id=server_id,
                old_status=status_history.old_status,
                new_status=status_history.new_status,
                timestamp=status_history.created_at
            )

        except Exception as e:
            # 更新状态为错误
            await self.server_repo.update_server_status(
                server_id, ServerStatus.ERROR.value, current_user_id, f"启动失败: {str(e)}"
            )
            raise ServerOperationError(f"服务器启动失败: {str(e)}")

    async def stop_server(self, server_id: int, current_user_id: int, comment: str = "手动停止") -> ServerStatusUpdate:
        """停止服务器""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 检查服务器状态
        if not server.can_stop():
            raise InvalidOperationException(f"服务器当前状态为 {server.status}，无法停止")

        # 更新状态为停止中
        await self.server_repo.update_server_status(server_id, ServerStatus.STOPPING.value, current_user_id, comment)

        try:
            # 尝试优雅停止
            if server.pid:
                await self._graceful_stop_server(server)
            else:
                # 如果没有PID，使用RCON停止
                await self._rcon_stop_server(server)

            # 等待服务器停止
            await self._wait_for_server_stop(server_id)

            # 更新状态为已停止
            status_history = await self.server_repo.update_server_status(
                server_id, ServerStatus.STOPPED.value, current_user_id, comment
            )

            # 记录日志
            await self.log_service.add_server_log(
                server_id=server_id,
                log_type="system",
                log_level="info",
                message=f"服务器停止成功",
                source="server_service"
            )

            return ServerStatusUpdate(
                server_id=server_id,
                old_status=status_history.old_status,
                new_status=status_history.new_status,
                timestamp=status_history.created_at
            )

        except Exception as e:
            # 更新状态为错误
            await self.server_repo.update_server_status(
                server_id, ServerStatus.ERROR.value, current_user_id, f"停止失败: {str(e)}"
            )
            raise ServerOperationError(f"服务器停止失败: {str(e)}")

    async def restart_server(self, server_id: int, current_user_id: int, comment: str = "手动重启") -> ServerStatusUpdate:
        """重启服务器""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 检查服务器状态
        if not server.can_restart():
            raise InvalidOperationException(f"服务器当前状态为 {server.status}，无法重启")

        # 先停止服务器
        await self.stop_server(server_id, current_user_id, f"重启前停止: {comment}")

        # 再启动服务器
        return await self.start_server(server_id, current_user_id, f"重启后启动: {comment}")

    async def install_server(self, server_id: int, current_user_id: int) -> bool:
        """安装游戏服务器""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 检查服务器状态
        if server.status != ServerStatus.STOPPED.value:
            raise InvalidOperationException(f"服务器当前状态为 {server.status}，无法安装")

        # 更新状态为安装中
        await self.server_repo.update_server_status(server_id, ServerStatus.INSTALLING.value, current_user_id, "开始安装服务器")

        try:
            # 创建安装目录
            await self._create_install_directory(server.install_path)

            # 使用SteamCMD安装服务器
            await self.steam_service.install_game_server(
                app_id=server.steam_app_id,
                install_path=server.install_path,
                branch=server.steam_branch,
                validate=server.validate_install
            )

            # 更新可执行文件路径
            executable_path = await self._detect_server_executable(server.install_path)
            await self.server_repo.update_server(server_id, ServerUpdate(executable_path=executable_path))

            # 更新服务器版本
            version = await self._detect_server_version(server.install_path)
            await self.server_repo.update_server(server_id, ServerUpdate(game_version=version))

            # 更新状态为已停止
            await self.server_repo.update_server_status(server_id, ServerStatus.STOPPED.value, current_user_id, "服务器安装完成")

            # 记录日志
            await self.log_service.add_server_log(
                server_id=server_id,
                log_type="installation",
                log_level="info",
                message=f"服务器安装成功，版本: {version}",
                source="server_service"
            )

            return True

        except Exception as e:
            # 更新状态为错误
            await self.server_repo.update_server_status(
                server_id, ServerStatus.ERROR.value, current_user_id, f"安装失败: {str(e)}"
            )
            raise ServerOperationError(f"服务器安装失败: {str(e)}")

    async def update_server_config(self, server_id: int, config_key: str, config_value: str, current_user_id: int) -> Any:
        """更新服务器配置""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 检查服务器状态 - 只有停止状态才能修改配置
        if server.status != ServerStatus.STOPPED.value:
            raise InvalidOperationException("只有停止状态的服务器才能修改配置")

        # 查找或创建配置
        config = await self.server_repo.get_server_config_by_key(server_id, config_key)
        if config:
            # 更新现有配置
            updated_config = await self.server_repo.update_server_config(
                config.id,
                ServerConfigUpdate(config_value=config_value, is_custom=True)
            )
        else:
            # 创建新配置
            updated_config = await self.server_repo.create_server_config(
                ServerConfigCreate(
                    server_id=server_id,
                    config_key=config_key,
                    config_value=config_value,
                    is_custom=True
                )
            )

        # 应用配置到实际文件
        await self._apply_config_to_file(server, config_key, config_value)

        return updated_config

    async def create_server_backup(self, server_id: int, backup_data: ServerBackupCreate, current_user_id: int) -> Any:
        """创建服务器备份""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 检查服务器状态
        if not server.can_backup():
            raise InvalidOperationException(f"服务器当前状态为 {server.status}，无法创建备份")

        # 生成备份名称（如果未提供）
        backup_name = backup_data.name or f"backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"

        # 更新状态为备份中
        await self.server_repo.update_server_status(server_id, ServerStatus.BACKING_UP.value, current_user_id, f"创建备份: {backup_name}")

        try:
            # 执行备份
            backup_result = await self.backup_service.create_backup(
                source_path=server.install_path,
                backup_name=backup_name,
                compression=backup_data.compression or "zstd",
                exclude_patterns=backup_data.exclude_patterns or ["*.log", "temp/*", "cache/*"]
            )

            # 创建备份记录
            backup_record = await self.server_repo.create_backup_record({
                "server_id": server_id,
                "backup_name": backup_name,
                "backup_path": backup_result["backup_path"],
                "size": backup_result["size"],
                "compression": backup_data.compression or "zstd",
                "version": server.game_version,
                "status": "completed",
                "duration": backup_result["duration"],
                "created_by": current_user_id,
                "is_auto": backup_data.is_auto or False,
                "retention_days": backup_data.retention_days or 7,
                "checksum": backup_result["checksum"]
            })

            # 恢复服务器状态
            original_status = ServerStatus.RUNNING.value if server.status_before_backup else ServerStatus.STOPPED.value
            await self.server_repo.update_server_status(server_id, original_status, current_user_id, "备份完成")

            # 记录日志
            await self.log_service.add_server_log(
                server_id=server_id,
                log_type="backup",
                log_level="info",
                message=f"备份创建成功: {backup_name}",
                source="server_service",
                details={"size": backup_result["size"], "duration": backup_result["duration"]}
            )

            # 清理旧备份
            if backup_data.auto_cleanup:
                await self._cleanup_old_backups(server_id, backup_data.retention_days or 7)

            return backup_record

        except Exception as e:
            # 恢复服务器状态
            original_status = ServerStatus.RUNNING.value if server.status_before_backup else ServerStatus.STOPPED.value
            await self.server_repo.update_server_status(server_id, original_status, current_user_id, f"备份失败: {str(e)}")
            raise ServerOperationError(f"备份创建失败: {str(e)}")

    async def add_server_mod(self, server_id: int, mod_data: ServerModCreate, current_user_id: int) -> Any:
        """添加服务器模组""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server:
            raise ResourceNotFoundError(f"服务器 ID {server_id} 不存在")

        # 检查权限
        await self._check_server_management_permission(server, current_user_id)

        # 检查服务器状态
        if server.status != ServerStatus.STOPPED.value:
            raise InvalidOperationException("只有停止状态的服务器才能添加模组")

        try:
            # 确定模组安装路径
            mod_path = os.path.join(server.install_path, "Mods")
            os.makedirs(mod_path, exist_ok=True)

            mod_info = {}

            # 如果提供了Workshop ID，通过SteamCMD下载
            if mod_data.workshop_id:
                mod_info = await self.steam_service.download_workshop_item(
                    app_id=server.steam_app_id,
                    workshop_id=mod_data.workshop_id,
                    install_path=mod_path
                )
            # 如果提供了URL，下载模组文件
            elif mod_data.url:
                mod_info = await self._download_mod_from_url(mod_data.url, mod_path, mod_data.mod_id)
            # 如果提供了文件路径，复制本地文件
            elif mod_data.local_path:
                mod_info = await self._copy_local_mod(mod_data.local_path, mod_path, mod_data.mod_id)
            else:
                raise InvalidOperationException("必须提供Workshop ID、URL或本地路径之一")

            # 合并模组信息
            final_mod_data = {
                "mod_id": mod_data.mod_id or mod_info.get("mod_id", f"mod_{uuid.uuid4().hex[:8]}"),
                "name": mod_data.name or mod_info.get("name", "未知模组"),
                "version": mod_data.version or mod_info.get("version", "未知版本"),
                "file_path": mod_info.get("file_path"),
                "workshop_id": mod_data.workshop_id or mod_info.get("workshop_id"),
                "enabled": mod_data.enabled,
                "load_order": mod_data.load_order or await self._get_next_mod_load_order(server_id),
                "hash": mod_info.get("hash"),
                "size": mod_info.get("size")
            }

            # 添加模组记录
            mod = await self.server_repo.add_server_mod(server_id, final_mod_data)

            # 记录日志
            await self.log_service.add_server_log(
                server_id=server_id,
                log_type="mod",
                log_level="info",
                message=f"模组添加成功: {final_mod_data['name']}",
                source="server_service",
                details={"mod_id": final_mod_data['mod_id'], "workshop_id": final_mod_data['workshop_id']}
            )

            return mod

        except Exception as e:
            raise ServerOperationError(f"添加模组失败: {str(e)}")

    async def _initialize_default_config(self, server_id: int) -> None:
        """初始化服务器默认配置"""
        # 获取默认配置模板
        default_configs = self._get_default_server_configs()

        # 批量创建配置
        for config in default_configs:
            await self.server_repo.create_server_config(
                ServerConfigCreate(
                    server_id=server_id,
                    config_key=config["key"],
                    config_value=config["value"],
                    category=config["category"],
                    description=config["description"],
                    is_custom=False
                )
            )

    async def _check_server_access_permission(self, server: Any, user_id: int) -> None:
        """检查用户是否有服务器访问权限""
        # 管理员可以访问所有服务器
        current_user = await self.user_repo.get_by_id(user_id)
        if current_user.role == 'admin':
            return

        # 服务器创建者可以访问
        if server.created_by == user_id:
            return

        # 检查用户是否有访问权限
        if not await self._has_server_access_role(server.id, user_id):
            raise PermissionDeniedError("没有访问该服务器的权限")

    async def _check_server_management_permission(self, server: Any, user_id: int) -> None:
        """检查用户是否有服务器管理权限""
        # 管理员可以管理所有服务器
        current_user = await self.user_repo.get_by_id(user_id)
        if current_user.role == 'admin':
            return

        # 服务器创建者可以管理
        if server.created_by == user_id:
            return

        # 检查用户是否有管理权限
        if not await self._has_server_management_role(server.id, user_id):
            raise PermissionDeniedError("没有管理该服务器的权限")

    async def _has_server_creation_permission(self, user_id: int) -> bool:
        """检查用户是否有创建服务器的权限""
        # 获取用户的服务器数量
        user_servers = await self.server_repo.get_servers_by_user(user_id)

        # 获取用户角色的服务器数量限制
        current_user = await self.user_repo.get_by_id(user_id)
        max_servers = self._get_max_servers_for_role(current_user.role)

        return len(user_servers) < max_servers

    def _get_max_servers_for_role(self, role: str) -> int:
        """获取角色的最大服务器数量限制""
        role_limits = {
            'admin': settings.ADMIN_MAX_SERVERS,
            'premium': settings.PREMIUM_MAX_SERVERS,
            'user': settings.DEFAULT_MAX_SERVERS
        }
        return role_limits.get(role, settings.DEFAULT_MAX_SERVERS)

    async def _is_server_installed(self, server: Any) -> bool:
        """检查服务器是否已安装""
        if not server.executable_path:
            return False

        return os.path.exists(server.executable_path)

    async def _create_install_directory(self, path: str) -> None:
        """创建安装目录""
        if os.path.exists(path):
            if not os.path.isdir(path):
                raise ConfigurationError(f"路径 {path} 已存在但不是目录")
            # 清空目录
            for item in os.listdir(path):
                item_path = os.path.join(path, item)
                if os.path.isfile(item_path):
                    os.remove(item_path)
                elif os.path.isdir(item_path):
                    shutil.rmtree(item_path)
        else:
            # 创建目录
            os.makedirs(path, exist_ok=True)

    async def _detect_server_executable(self, install_path: str) -> str:
        """检测服务器可执行文件路径""
        # 根据不同操作系统查找可执行文件
        if os.name == 'nt':
            # Windows系统
            executable_names = ['PalServer.exe', 'PalWorldServer.exe']
        else:
            # Linux系统
            executable_names = ['PalServer.sh', 'PalWorldServer', 'start-server.sh']

        # 递归搜索可执行文件
        for root, dirs, files in os.walk(install_path):
            for name in executable_names:
                if name in files:
                    return os.path.join(root, name)

        raise ConfigurationError(f"在 {install_path} 中未找到服务器可执行文件")

    async def _detect_server_version(self, install_path: str) -> str:
        """检测服务器版本""
        # 尝试从版本文件中读取
        version_files = [
            os.path.join(install_path, 'version.txt'),
            os.path.join(install_path, 'CHANGELOG.md'),
            os.path.join(install_path, 'steam_api.dll')  # Windows DLL文件
        ]

        for file_path in version_files:
            if os.path.exists(file_path):
                if file_path.endswith('.dll'):
                    # 读取DLL版本信息
                    try:
                        import win32api
                        info = win32api.GetFileVersionInfo(file_path, '\\')
                        ms = info['FileVersionMS']
                        ls = info['FileVersionLS']
                        version = f"{ms >> 16}.{ms & 0xFFFF}.{ls >> 16}.{ls & 0xFFFF}"
                        return version
                    except:
                        continue
                else:
                    # 读取文本文件
                    with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                        content = f.read(1000)
                        # 使用正则表达式查找版本号
                        match = re.search(r'(\d+\.\d+\.\d+\.\d+|\d+\.\d+\.\d+)', content)
                        if match:
                            return match.group(1)

        # 如果找不到版本信息，返回未知版本
        return 'unknown'

    async def _execute_server_start(self, server: Any) -> None:
        """执行服务器启动命令""
        # 获取服务器配置
        configs = await self.server_repo.get_server_configs(server.id)
        config_dict = {c.config_key: c.config_value for c in configs}

        # 构建启动参数
        start_params = self._build_server_start_params(config_dict, server)

        # 构建工作目录
        working_dir = os.path.dirname(server.executable_path)

        # 创建日志文件
        log_dir = os.path.join(working_dir, 'logs')
        os.makedirs(log_dir, exist_ok=True)
        log_file = os.path.join(log_dir, f"server_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log")

        try:
            # 启动进程
            if os.name == 'nt':
                # Windows系统
                process = subprocess.Popen(
                    [server.executable_path] + start_params,
                    cwd=working_dir,
                    stdout=open(log_file, 'w'),
                    stderr=subprocess.STDOUT,
                    creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
                )
            else:
                # Linux系统
                process = subprocess.Popen(
                    [server.executable_path] + start_params,
                    cwd=working_dir,
                    stdout=open(log_file, 'w'),
                    stderr=subprocess.STDOUT,
                    preexec_fn=os.setsid
                )

            # 更新服务器PID
            await self.server_repo.update_server(server.id, ServerUpdate(pid=process.pid))

        except Exception as e:
            raise ServerOperationError(f"无法启动服务器进程: {str(e)}")

    async def _wait_for_server_start(self, server_id: int, timeout: int = 300) -> None:
        """等待服务器启动完成""
        server = await self.server_repo.get_server_by_id(server_id)
        start_time = datetime.now()

        while (datetime.now() - start_time).total_seconds() < timeout:
            # 检查服务器是否响应RCON命令
            try:
                if await self.rcon_service.test_connection(server.ip, server.rcon_port, server.rcon_password):
                    return
            except:
                pass

            # 检查服务器日志是否有启动完成的标志
            if await self._check_server_log_for_startup_complete(server_id):
                return

            # 等待1秒后重试
            await asyncio.sleep(1)

        raise TimeoutError(f"服务器启动超时，超过 {timeout} 秒未响应")

    async def _check_server_log_for_startup_complete(self, server_id: int) -> bool:
        """检查服务器日志是否有启动完成的标志""
        server = await self.server_repo.get_server_by_id(server_id)
        if not server.executable_path:
            return False

        log_dir = os.path.join(os.path.dirname(server.executable_path), 'logs')
        if not os.path.exists(log_dir):
            return False

        # 获取最新的日志文件
        log_files = [f for f in os.listdir(log_dir) if f.endswith('.log')]
        if not log_files:
            return False

        latest_log = max(log_files, key=lambda x: os.path.getctime(os.path.join(log_dir, x)))
        log_path = os.path.join(log_dir, latest_log)

        # 读取日志文件末尾内容
        try:
            with open(log_path, 'r', encoding='utf-8', errors='ignore') as f:
                # 移动到文件末尾
                f.seek(0, os.SEEK_END)
                # 读取最后1000字节
                f.seek(max(f.tell() - 1000, 0), os.SEEK_SET)
                content = f.read()

                # 检查启动完成的标志
                startup_patterns = [
                    'server started', '服务器已启动', 'listening on port',
                    'RCON server started', '开始监听连接', 'server is ready'
                ]

                for pattern in startup_patterns:
                    if re.search(pattern, content, re.IGNORECASE):
                        return True

        except Exception as e:
            await self.log_service.add_server_log(
                server_id=server_id,
                log_type="system",
                log_level="warning",
                message=f"读取服务器日志失败: {str(e)}",
                source="server_service"
            )

        return False

    async def _graceful_stop_server(self, server: Any) -> None:
        """优雅停止服务器""
        try:
            # 尝试使用RCON发送停止命令
            await self.rcon_service.send_command(
                server.ip,
                server.rcon_port,
                server.rcon_password,
                "shutdown"
            )

            # 等待服务器进程结束
            await self._wait_for_process_exit(server.pid, timeout=30)

        except Exception as e:
            # RCON停止失败，尝试直接终止进程
            await self._force_stop_server(server.pid)
            raise ServerOperationError(f"RCON停止失败，已强制终止进程: {str(e)}")

    async def _rcon_stop_server(self, server: Any) -> None:
        """使用RCON停止服务器""
        try:
            # 发送停止命令
            await self.rcon_service.send_command(
                server.ip,
                server.rcon_port,
                server.rcon_password,
                "shutdown"
            )

            # 等待服务器停止
            await self._wait_for_server_stop(server.id)

        except Exception as e:
            raise ServerOperationError(f"RCON停止命令失败: {str(e)}")

    async def _wait_for_process_exit(self, pid: int, timeout: int = 30) -> None:
        """等待进程退出""
        start_time = datetime.now()

        while (datetime.now() - start_time).total_seconds() < timeout:
            try:
                # 检查进程是否存在
                if os.name == 'nt':
                    # Windows系统
                    output = subprocess.check_output(f'tasklist /fi "PID eq {pid}"', stderr=subprocess.STDOUT)
                    if f"{pid}" not in output.decode('gbk', errors='ignore'):
                        return
                else:
                    # Linux系统
                    os.kill(pid, 0)
            except:
                # 进程不存在
                return

            await asyncio.sleep(1)

        # 超时，强制终止进程
        await self._force_stop_server(pid)

    async def _force_stop_server(self, pid: int) -> None:
        """强制停止服务器进程""
        try:
            if os.name == 'nt':
                # Windows系统
                subprocess.check_call(f'taskkill /PID {pid} /F /T', stderr=subprocess.STDOUT)
            else:
                # Linux系统
                os.killpg(os.getpgid(pid), signal.SIGKILL)
        except Exception as e:
            raise ServerOperationError(f"强制终止进程失败: {str(e)}")

    async def _wait_for_server_stop(self, server_id: int, timeout: int = 60) -> None:
        """等待服务器停止""
        start_time = datetime.now()

        while (datetime.now() - start_time).total_seconds() < timeout:
            server = await self.server_repo.get_server_by_id(server_id)
            if server.status == ServerStatus.STOPPED.value:
                return
            await asyncio.sleep(1)

        raise TimeoutError(f"服务器停止超时，超过 {timeout} 秒")

    async def _apply_config_to_file(self, server: Any, config_key: str, config_value: str) -> None:
        """将配置应用到实际文件""
        if not server.executable_path:
            raise ConfigurationError("服务器可执行文件路径未设置")

        # 确定配置文件路径
        config_file_path = self._get_server_config_file_path(server)
        if not os.path.exists(config_file_path):
            raise ConfigurationError(f"配置文件不存在: {config_file_path}")

        # 根据配置文件类型应用配置
        if config_file_path.endswith('.ini') or config_file_path.endswith('.cfg'):
            await self._update_ini_config(config_file_path, config_key, config_value)
        elif config_file_path.endswith('.json'):
            await self._update_json_config(config_file_path, config_key, config_value)
        elif config_file_path.endswith('.xml'):
            await self._update_xml_config(config_file_path, config_key, config_value)
        else:
            # 通用文本替换
            await self._update_text_config(config_file_path, config_key, config_value)

    def _get_server_config_file_path(self, server: Any) -> str:
        """获取服务器配置文件路径""
        # 根据服务器类型返回默认配置文件路径
        executable_dir = os.path.dirname(server.executable_path)
        if 'PalWorld' in server.name or 'PalServer' in server.executable_path:
            # 幻兽帕鲁服务器
            if os.name == 'nt':
                return os.path.join(executable_dir, 'Pal/Saved/Config/WindowsServer/PalWorldSettings.ini')
            else:
                return os.path.join(executable_dir, 'Pal/Saved/Config/LinuxServer/PalWorldSettings.ini')
        else:
            # 默认配置路径
            return os.path.join(executable_dir, 'config.ini')

    async def _update_ini_config(self, file_path: str, config_key: str, config_value: str) -> None:
        """更新INI格式配置文件""
        import configparser

        config = configparser.ConfigParser()
        config.read(file_path, encoding='utf-8')

        # 支持section.key格式的配置键
        if '.' in config_key:
            section, key = config_key.split('.', 1)
        else:
            section = 'ServerSettings'
            key = config_key

        # 确保section存在
        if section not in config:
            config.add_section(section)

        # 设置配置值
        config.set(section, key, config_value)

        # 保存配置文件
        with open(file_path, 'w', encoding='utf-8') as f:
            config.write(f)

    async def _update_json_config(self, file_path: str, config_key: str, config_value: str) -> None:
        """更新JSON格式配置文件""
        with open(file_path, 'r', encoding='utf-8') as f:
            config = json.load(f)

        # 支持嵌套键，如server.port
        keys = config_key.split('.')
        current = config
        for i, key in enumerate(keys):
            if i == len(keys) - 1:
                # 最后一个键，设置值
                current[key] = self._parse_config_value(config_value)
            else:
                # 确保父键存在
                if key not in current:
                    current[key] = {}
                current = current[key]

        # 保存配置文件
        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(config, f, indent=4, ensure_ascii=False)

    async def _update_xml_config(self, file_path: str, config_key: str, config_value: str) -> None:
        """更新XML格式配置文件""
        import xml.etree.ElementTree as ET

        tree = ET.parse(file_path)
        root = tree.getroot()

        # 查找配置节点
        node = root.find(config_key)
        if node is None:
            # 创建新节点
            parent_path, node_name = os.path.split(config_key)
            if parent_path:
                parent_node = root.find(parent_path)
                if parent_node is None:
                    raise ConfigurationError(f"XML配置中找不到父节点: {parent_path}")
            else:
                parent_node = root

            node = ET.SubElement(parent_node, node_name)

        # 设置节点值
        node.text = config_value

        # 保存配置文件
        tree.write(file_path, encoding='utf-8', xml_declaration=True)

    async def _update_text_config(self, file_path: str, config_key: str, config_value: str) -> None:
        """更新文本格式配置文件（行匹配替换）""
        with open(file_path, 'r', encoding='utf-8') as f:
            lines = f.readlines()

        # 查找并替换配置行
        found = False
        for i, line in enumerate(lines):
            if line.strip().startswith(config_key) and '=' in line:
                # 保留注释部分
                if '#' in line or ';' in line:
                    separator = '#' if '#' in line else ';'
                    comment = line.split(separator, 1)[1]
                    lines[i] = f"{config_key}={config_value} {separator}{comment}"
                else:
                    lines[i] = f"{config_key}={config_value}\n"
                found = True
                break

        if not found:
            # 添加新配置行
            lines.append(f"{config_key}={config_value}\n")

        # 保存配置文件
        with open(file_path, 'w', encoding='utf-8') as f:
            f.writelines(lines)

    def _parse_config_value(self, value: str) -> Any:
        """解析配置值为适当的类型""
        # 尝试解析为布尔值
        if value.lower() == 'true':
            return True
        if value.lower() == 'false':
            return False

        # 尝试解析为整数
        try:
            return int(value)
        except ValueError:
            pass

        # 尝试解析为浮点数
        try:
            return float(value)
        except ValueError:
            pass

        # 尝试解析为JSON
        try:
            return json.loads(value)
        except ValueError:
            pass

        # 作为字符串返回
        return value

    def _get_default_server_configs(self) -> List[Dict[str, str]]:
        """获取服务器默认配置""
        return [
            {
                "key": "ServerName",
                "value": "幻兽帕鲁服务器",
                "category": "general",
                "description": "服务器名称"
            },
            {
                "key": "ServerDescription",
                "value": "欢迎来到幻兽帕鲁服务器",
                "category": "general",
                "description": "服务器描述"
            },
            {
                "key": "MaxPlayers",
                "value": "32",
                "category": "general",
                "description": "最大玩家数"
            },
            {
                "key": "ServerPassword",
                "value": "",
                "category": "security",
                "description": "服务器密码"
            },
            {
                "key": "RCONEnabled",
                "value": "True",
                "category": "rcon",
                "description": "是否启用RCON"
            },
            {
                "key": "RCONPort",
                "value": "25575",
                "category": "rcon",
                "description": "RCON端口"
            },
            {
                "key": "RCONPassword",
                "value": "",
                "category": "security",
                "description": "RCON密码"
            },
            {
                "key": "PublicServer",
                "value": "False",
                "category": "general",
                "description": "是否公开服务器"
            },
            {
                "key": "PvP",
                "value": "False",
                "category": "gameplay",
                "description": "是否启用PvP"
            },
            {
                "key": "DayTimeSpeedRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "白天速度倍率"
            },
            {
                "key": "NightTimeSpeedRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "夜晚速度倍率"
            },
            {
                "key": "ExpRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "经验倍率"
            },
            {
                "key": "PalCaptureRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "帕鲁捕捉倍率"
            },
            {
                "key": "PalSpawnNumRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "帕鲁生成数量倍率"
            },
            {
                "key": "PalDamageRateAttack",
                "value": "1.0",
                "category": "gameplay",
                "description": "帕鲁攻击伤害倍率"
            },
            {
                "key": "PalDamageRateDefense",
                "value": "1.0",
                "category": "gameplay",
                "description": "帕鲁防御伤害倍率"
            },
            {
                "key": "PlayerDamageRateAttack",
                "value": "1.0",
                "category": "gameplay",
                "description": "玩家攻击伤害倍率"
            },
            {
                "key": "PlayerDamageRateDefense",
                "value": "1.0",
                "category": "gameplay",
                "description": "玩家防御伤害倍率"
            },
            {
                "key": "PlayerStomachDecreaceRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "玩家饱食度减少倍率"
            },
            {
                "key": "PlayerStaminaDecreaceRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "玩家耐力减少倍率"
            },
            {
                "key": "PlayerAutoHPRegeneRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "玩家自动HP恢复倍率"
            },
            {
                "key": "PlayerAutoHpRegeneRateInSleep",
                "value": "1.0",
                "category": "gameplay",
                "description": "玩家睡眠时HP恢复倍率"
            },
            {
                "key": "PalStomachDecreaceRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "帕鲁饱食度减少倍率"
            },
            {
                "key": "PalStaminaDecreaceRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "帕鲁耐力减少倍率"
            },
            {
                "key": "PalAutoHPRegeneRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "帕鲁自动HP恢复倍率"
            },
            {
                "key": "PalAutoHpRegeneRateInSleep",
                "value": "1.0",
                "category": "gameplay",
                "description": "帕鲁睡眠时HP恢复倍率"
            },
            {
                "key": "BuildObjectDamageRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "建筑伤害倍率"
            },
            {
                "key": "BuildObjectDeteriorationDamageRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "建筑劣化伤害倍率"
            },
            {
                " key": "CollectionDropRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "采集掉落倍率"
            },
            {
                "key": "CollectionObjectHpRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "采集对象HP倍率"
            },
            {
                "key": "CollectionObjectRespawnSpeedRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "采集对象重生速度倍率"
            },
            {
                "key": "EnemyDropItemRate",
                "value": "1.0",
                "category": "gameplay",
                "description": "敌人掉落物品倍率"
            },
            {
                "key": "DeathPenalty",
                "value": "All",
                "category": "gameplay",
                "description": "死亡惩罚 (None, Item, Equipment, All)"
            },
            {
                "key": "bEnablePlayerToPlayerDamage",
                "value": "False",
                "category": "pvp",
                "description": "启用玩家对玩家伤害"
            },
            {
                "key": "bEnableFriendlyFire",
                "value": "False",
                "category": "pvp",
                "description": "启用友军伤害"
            },
            {
                "key": "bEnableInvaderEnemy",
                "value": "True",
                "category": "gameplay",
                "description": "启用入侵敌人"
            },
            {
                "key": "CoopPlayerMaxNum",
                "value": "4",
                "category": "general",
                "description": "合作玩家最大数量"
            },
            {
                "key": "ServerPlayerMaxNum",
                "value": "32",
                "category": "general",
                "description": "服务器玩家最大数量"
            },
            {
                "key": "ServerPort",
                "value": "8211",
                "category": "network",
                "description": "服务器端口"
            },
            {
                "key": "LogFormat",
                "value": "Text",
                "category": "logging",
                "description": "日志格式 (Text, Json)"
            }
        ]

    async def _has_server_creation_permission(self, user_id: int) -> bool:
        """检查用户是否有创建服务器的权限""
        user = await self.user_repo.get_by_id(user_id)
        if not user:
            return False

        # 管理员和高级用户有创建权限
        if user.role in ['admin', 'premium']:
            return True

        # 检查普通用户的服务器数量
        user_servers = await self.server_repo.get_servers_by_user(user_id)
        return len(user_servers) < settings.DEFAULT_MAX_SERVERS

    async def _check_server_access_permission(self, server: Any, user_id: int) -> None:
        """检查服务器访问权限""
        # 管理员可以访问所有服务器
        current_user = await self.user_repo.get_by_id(user_id)
        if current_user.role == 'admin':
            return

        # 服务器创建者可以访问
        if server.created_by == user_id:
            return

        # 检查用户是否有访问权限
        if not await self._has_server_access_role(server.id, user_id):
            raise PermissionDeniedError("没有访问该服务器的权限")

    async def _has_server_access_role(self, server_id: int, user_id: int) -> bool:
        """检查用户是否有服务器访问角色""
        # 这里应该检查用户是否在服务器的授权用户列表中
        # 简化实现，实际项目中应该查询user_server_roles表
        return False

    async def _has_server_management_role(self, server_id: int, user_id: int) -> bool:
        """检查用户是否有服务器管理角色""
        # 这里应该检查用户是否有服务器的管理权限
        # 简化实现，实际项目中应该查询user_server_roles表
        return False

    async def _get_next_mod_load_order(self, server_id: int) -> int:
        """获取下一个模组的加载顺序""
        mods = await self.server_repo.get_server_mods(server_id)
        if not mods:
            return 0
        return max(mod.load_order for mod in mods) + 1

    async def _download_mod_from_url(self, url: str, mod_path: str, mod_id: str) -> Dict[str, Any]:
        """从URL下载模组""
        import aiohttp

        mod_info = {
            "mod_id": mod_id,
            "name": os.path.basename(url),
            "file_path": os.path.join(mod_path, os.path.basename(url))
        }

        # 创建临时文件
        temp_file = os.path.join(mod_path, f"temp_{uuid.uuid4().hex[:8]}_{os.path.basename(url)}")

        try:
            # 下载文件
            async with aiohttp.ClientSession() as session:
                async with session.get(url) as response:
                    if response.status != 200:
                        raise HTTPException(status_code=response.status, detail=f"下载失败: {response.reason}")

                    with open(temp_file, 'wb') as f:
                        async for chunk in response.content.iter_chunked(8192):
                            f.write(chunk)

            # 计算文件哈希
            mod_info["hash"] = await self._calculate_file_hash(temp_file)

            # 获取文件大小
            mod_info["size"] = os.path.getsize(temp_file)

            # 如果是压缩文件，解压
            if temp_file.endswith(('.zip', '.rar', '.7z', '.tar', '.tar.gz', '.tar.bz2')):
                import zipfile
                import tarfile

                extract_dir = os.path.join(mod_path, mod_id)
                os.makedirs(extract_dir, exist_ok=True)

                if temp_file.endswith('.zip'):
                    with zipfile.ZipFile(temp_file, 'r') as zip_ref:
                        zip_ref.extractall(extract_dir)
                elif temp_file.endswith(('.tar', '.tar.gz', '.tar.bz2')):
                    with tarfile.open(temp_file, 'r') as tar_ref:
                        tar_ref.extractall(extract_dir)

                mod_info["file_path"] = extract_dir
                os.remove(temp_file)
            else:
                # 移动文件到最终位置
                os.rename(temp_file, mod_info["file_path"])

            return mod_info

        except Exception as e:
            if os.path.exists(temp_file):
                os.remove(temp_file)
            raise ServerOperationError(f"下载模组失败: {str(e)}")

    async def _copy_local_mod(self, local_path: str, mod_path: str, mod_id: str) -> Dict[str, Any]:
        """复制本地模组文件""
        if not os.path.exists(local_path):
            raise FileNotFoundError(f"本地文件/目录不存在: {local_path}")

        mod_info = {
            "mod_id": mod_id,
            "name": os.path.basename(local_path),
        }

        destination = os.path.join(mod_path, mod_id)
        os.makedirs(os.path.dirname(destination), exist_ok=True)

        try:
            if os.path.isfile(local_path):
                # 复制文件
                shutil.copy2(local_path, destination)
                mod_info["file_path"] = destination
                mod_info["size"] = os.path.getsize(destination)
                mod_info["hash"] = await self._calculate_file_hash(destination)
            else:
                # 复制目录
                if os.path.exists(destination):
                    shutil.rmtree(destination)
                shutil.copytree(local_path, destination)
                mod_info["file_path"] = destination
                mod_info["size"] = await self._calculate_directory_size(destination)
                mod_info["hash"] = await self._calculate_directory_hash(destination)

            return mod_info

        except Exception as e:
            raise ServerOperationError(f"复制本地模组失败: {str(e)}")

    async def _calculate_file_hash(self, file_path: str) -> str:
        """计算文件哈希值""
        hash_sha256 = hashlib.sha256()
        with open(file_path, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), b''):
                hash_sha256.update(chunk)
        return hash_sha256.hexdigest()

    async def _calculate_directory_hash(self, dir_path: str) -> str:
        """计算目录哈希值""
        hash_sha256 = hashlib.sha256()

        for root, dirs, files in os.walk(dir_path):
            for file in sorted(files):
                file_path = os.path.join(root, file)
                file_hash = await self._calculate_file_hash(file_path)
                hash_sha256.update(file_hash.encode('utf-8'))

        return hash_sha256.hexdigest()

    async def _calculate_directory_size(self, dir_path: str) -> int:
        """计算目录大小""
        total_size = 0
        for root, dirs, files in os.walk(dir_path):
            for file in files:
                file_path = os.path.join(root, file)
                total_size += os.path.getsize(file_path)
        return total_size

    async def _cleanup_old_backups(self, server_id: int, retention_days: int) -> None:
        """清理旧备份""
        backups = await self.server_repo.get_server_backups(server_id)
        cutoff_date = datetime.now() - timedelta(days=retention_days)

        for backup in backups:
            if backup.created_at < cutoff_date and not backup.is_protected:
                # 删除备份文件
                if os.path.exists(backup.backup_path):
                    try:
                        os.remove(backup.backup_path)
                    except Exception as e:
                        await self.log_service.add_server_log(
                            server_id=server_id,
                            log_type="backup",
                            log_level="warning",
                            message=f"删除旧备份文件失败: {str(e)}",
                            source="server_service",
                            details={"backup_id": backup.id, "path": backup.backup_path}
                        )

                # 删除备份记录
                await self.server_repo.delete_backup(backup.id)

                # 记录日志
                await self.log_service.add_server_log(
                    server_id=server_id,
                    log_type="backup",
                    log_level="info",
                    message=f"已清理旧备份: {backup.backup_name}",
                    source="server_service",
                    details={"backup_id": backup.id, "age_days": (datetime.now() - backup.created_at).days}
                )

    async def _build_server_start_params(self, configs: Dict[str, str], server: Any) -> List[str]:
        """构建服务器启动参数""
        params = []

        # 添加基本启动参数
        if 'PalWorld' in server.name or 'PalServer' in server.executable_path:
            # 幻兽帕鲁服务器特有参数
            params.extend([
                f"-port={server.port}",
                f"-maxplayers={configs.get('MaxPlayers', server.max_players)}",
                f"-servername={configs.get('ServerName', 'PalServer')}",
                f"-serverpassword={configs.get('ServerPassword', '')}",
                f"-rconport={server.rcon_port}",
                f"-rconpassword={server.rcon_password}",
                f"-publicserver={configs.get('PublicServer', 'False')}"
            ])
        else:
            # 通用服务器参数
            params.extend([
                f"--port={server.port}",
                f"--max-players={configs.get('MaxPlayers', server.max_players)}",
                f"--name={configs.get('ServerName', 'GameServer')}"
            ])

        # 添加自定义启动参数
        if configs.get('CustomLaunchParams'):
            custom_params = configs['CustomLaunchParams'].split()
            params.extend(custom_params)

        return params

    async def _execute_server_start(self, server: Any) -> None:
        """执行服务器启动命令""
        # 获取服务器配置
        configs = await self.server_repo.get_server_configs(server.id)
        config_dict = {c.config_key: c.config_value for c in configs}

        # 构建启动参数
        start_params = self._build_server_start_params(config_dict, server)

        # 构建工作目录
        working_dir = os.path.dirname(server.executable_path)

        # 创建日志文件
        log_dir = os.path.join(working_dir, 'logs')
        os.makedirs(log_dir, exist_ok=True)
        log_file = os.path.join(log_dir, f"server_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log")

        try:
            # 启动进程
            if os.name == 'nt':
                # Windows系统
                process = subprocess.Popen(
                    [server.executable_path] + start_params,
                    cwd=working_dir,
                    stdout=open(log_file, 'w'),
                    stderr=subprocess.STDOUT,
                    creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
                )
            else:
                # Linux系统
                process = subprocess.Popen(
                    [server.executable_path] + start_params,
                    cwd=working_dir,
                    stdout=open(log_file, 'w'),
                    stderr=subprocess.STDOUT,
                    preexec_fn=os.setsid
                )

            # 更新服务器PID
            await self.server_repo.update_server(server.id, ServerUpdate(pid=process.pid))

        except Exception as e:
            raise ServerOperationError(f"无法启动服务器进程: {str(e)}")

    async def _wait_for_server_stop(self, server_id: int, timeout: int = 60) -> None:
        """等待服务器停止""
        start_time = datetime.now()

        while (datetime.now() - start_time).total_seconds() < timeout:
            server = await self.server_repo.get_server_by_id(server_id)
            if server.status == ServerStatus.STOPPED.value:
                return
            await asyncio.sleep(1)

        raise TimeoutError(f"服务器停止超时，超过 {timeout} 秒")